owner = game.Players.WomanMalder local Song = {} Song.__index = Song local HttpService = game:GetService('HttpService') local MIDI = loadstring(HttpService:GetAsync('https://raw.githubusercontent.com/richie0866/MidiPlayer/main/src/MIDI.lua'))() local RunService = game:GetService("RunService") local HttpService = game:GetService('HttpService') local function GetTimeLength(score) local length = 0 for i, track in ipairs(score) do if (i == 1) then continue end length = math.max(length, track[#track][2]) end return length end function Song.new(file) local midiData = HttpService:GetAsync(file) local score = MIDI.midi2score(midiData) local fullname = file:match("([^/^\\]+)$") local name = fullname:match("^([^%.]+)") or "" local self = setmetatable({ Name = name; FullName = fullname:gsub('%%20',' '):gsub('\?.+',''); Path = file; TimePosition = 0; TimeLength = 0; Timebase = score[1]; IsPlaying = false; _score = score; _usPerBeat = 0; _lastTimePosition = 0; _length = GetTimeLength(score); _eventStatus = {}; _updateConnection = nil; }, {__index = Song}) self.TimeLength = (self._length / self.Timebase) return self end function Song:Update(timePosition, lastTimePosition) for _,track in next, self._score,1 do for _,event in ipairs(track) do local eventTime = (event[2] / self.Timebase) if (timePosition >= eventTime) then if (lastTimePosition <= eventTime) then self:_parse(event) end end end end end function Song:Step(deltaTime) self._lastTimePosition = self.TimePosition if (self._usPerBeat ~= 0) then self.TimePosition += (deltaTime / (self._usPerBeat / 1000000)) else self.TimePosition += deltaTime end end function Song:Play() self._updateConnection = RunService.Heartbeat:Connect(function(dt) self:Update(self.TimePosition, self._lastTimePosition) self:Step(dt) if (self.TimePosition >= self.TimeLength) then self:Pause() end end) self:Update(0, 0) self.IsPlaying = true end function Song:Stop() if (self._updateConnection) then self._updateConnection:Disconnect() self._updateConnection = nil self.IsPlaying = false end self._lastTimePosition = 0 end function Song:Pause() if (self._updateConnection) then self._updateConnection:Disconnect() self._updateConnection = nil self.IsPlaying = false end end local ExistingSounds = {} local Instruments = { -- Generic -- ['MS Piano'] = {"rbxassetid://5924276201", -8}, ['Grand Piano'] = {'rbxassetid://5479882728', -1}, Piano = {'rbxassetid://584691395' , -1}, ['Piano Fret'] = {'rbxassetid://584691395' , -1}, Bell = {'rbxassetid://19344667' , -7}, Harp = {'rbxassetid://109618842' , -13}, Sitar = {'rbxassetid://12857654' , -1}, Guitar = {'rbxassetid://4007485270', 0}, Doo = {'rbxassetid://75338648' , -2}, ['Breathy Brass'] = {'rbxassetid://11998777' , 11}, Baritone = {'rbxassetid://1846986991', 6}, Violin = {'rbxassetid://13418521' , 3}, Dulcheimer = {'rbxassetid://9040512197', 2}, ['English Horn'] = {'rbxassetid://13417380' , -7}, Bassoon = {'rbxassetid://13424334' ,-12}, -- Waves -- Square = {'rbxassetid://9040512330', 2}, Sawtooth = {'rbxassetid://9040512075', 2}, Sine = {'rbxassetid://146750669' , 2}, Dial = {'rbxassetid://15666462' , -2}, Calliope = {'rbxassetid://9040512197', 2}, -- Memes -- Chinese = {'rbxassetid://775395533',-7}, } local PianoSound = Instruments["MS Piano"] function notetopitch(note, offset) return ((440 / 32) * math.pow(2, ((note + offset) / 12)) / 440)*8 end local ContentProvider = game:GetService("ContentProvider") ContentProvider:Preload(PianoSound[1]) local noteHex = {'00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0A', '0B', '0C', '0D', '0E', '0F', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1A', '1B', '1C', '1D', '1E', '1F', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2A', '2B', '2C', '2D', '2E', '2F', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3A', '3B', '3C', '3D', '3E', '3F', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4A', '4B', '4C', '4D', '4E', '4F', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5A', '5B', '5C', '5D', '5E', '5F', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6A', '6B', '6C', '6D', '6E', '6F', '70', '71', '72', '73', '74', '75', '76', '77',} local noteNames = {"C ","C#","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B","C","C♯","D","D♯","E","F","F♯","G","G♯","A","A♯","B"} local Highnotes = {2,4,7, 9, 11, 14,16, 19, 21, 23, 26, 28 ,31, 33, 35 ,38 ,40, 43, 45 ,47, 50 ,52 ,55 ,57, 59} local function playNote(note, time, volume) local note2 = (note - 1)%12 + 1 -- Which note? (1-12) local octave = math.ceil(note/12) -- Which octave? local sound = math.ceil(note2/2) -- Which audio? local offset = 16 * (octave - 1) + 8 * (1 - note2%2) -- How far in audio? local audio = Instance.new("Sound", owner.Character.Head)-- Create the audio audio.SoundId = PianoSound[1] audio.PlaybackSpeed = notetopitch(note, PianoSound[2]) audio.Volume = volume audio.RollOffMaxDistance = 100 audio:Play() -- Play the audio task.delay(time,function() game:GetService('TweenService'):Create(audio,TweenInfo.new(.25),{Volume = 0}):Play() end) game:GetService("Debris"):AddItem(audio,8) end local pianoBillboard = Instance.new("BillboardGui") pianoBillboard.Enabled = false local pianoBox = Instance.new("TextBox") pianoBillboard.Name = "maliceBillboard" pianoBillboard.Parent = owner.Character.Head or workspace pianoBillboard.Size = UDim2.new(10, 0, 0.7, 0) pianoBillboard.Adornee = owner.Character.Head or workspace pianoBillboard.StudsOffset = Vector3.new(3, 1.5, 0) pianoBox.Name = "talkBox" pianoBox.Parent = pianoBillboard pianoBox.Size = UDim2.new(1, 0, 1, 0) pianoBox.AutoLocalize = false pianoBox.Localize = false pianoBox.BackgroundColor = BrickColor.new("Institutional white") pianoBox.BackgroundColor3 = Color3.new(1, 1, 1) pianoBox.BackgroundTransparency = 1 pianoBox.Font = Enum.Font.SourceSans pianoBox.FontSize = Enum.FontSize.Size18 pianoBox.Text = "🎹" pianoBox.TextColor = BrickColor.new("Institutional white") pianoBox.TextColor3 = Color3.new(1, 1, 1) pianoBox.TextScaled = true pianoBox.TextSize = 18 pianoBox.TextStrokeTransparency = 1 pianoBox.TextWrap = true pianoBox.TextWrapped = true pianoBox.RichText = true local percussionBillboard = Instance.new("BillboardGui") percussionBillboard.Enabled = false local percussionBox = Instance.new("TextBox") percussionBillboard.Name = "maliceBillboard" percussionBillboard.Parent = owner.Character.Head or workspace percussionBillboard.Size = UDim2.new(10, 0, 0.7, 0) percussionBillboard.Adornee = owner.Character.Head or workspace percussionBillboard.StudsOffset = Vector3.new(-3, 1.5, 0) percussionBox.Name = "talkBox" percussionBox.Parent = percussionBillboard percussionBox.Size = UDim2.new(1, 0, 1, 0) percussionBox.AutoLocalize = false percussionBox.Localize = false percussionBox.BackgroundColor = BrickColor.new("Institutional white") percussionBox.BackgroundColor3 = Color3.new(1, 1, 1) percussionBox.BackgroundTransparency = 1 percussionBox.Font = Enum.Font.SourceSans percussionBox.FontSize = Enum.FontSize.Size18 percussionBox.Text = "🥁" percussionBox.TextColor = BrickColor.new("Institutional white") percussionBox.TextColor3 = Color3.new(1, 1, 1) percussionBox.TextScaled = true percussionBox.TextSize = 18 percussionBox.TextStrokeTransparency = 1 percussionBox.TextWrap = true percussionBox.TextWrapped = true percussionBox.RichText = true local mainPart = Instance.new('Part',owner.Character) mainPart.Size = Vector3.new(5.2,5,0.1) mainPart.Transparency = 1 mainPart.CanCollide = false local mainPWeld = Instance.new('Motor6D',mainPart) mainPWeld.Part0 = owner.Character.Head mainPWeld.Part1 = mainPart mainPWeld.C0 = CFrame.new(0,4.75,0) local blackKeys = {'2','5','7','10','12','14','17','19','22','24','26','29','31','34','36','38','41','43','46','48','50','53','55','58','60','62','65','67','70','72','74','77','79','82','84','86'} do local s = 1 for i=1,88 do local _key = Instance.new('Part',mainPart) _key.Material = 'SmoothPlastic' _key.CanCollide = false _key.Massless = true local _keyweld = Instance.new('Motor6D',_key) _keyweld.Part0 = _key _keyweld.Part1 = mainPart --print(tostring(i)) _key.Name = i if(table.find(blackKeys,tostring(i))) then --print'as' _key.Color = Color3.new() _key.Size = Vector3.new(.05,.45,.005) _keyweld.C0 = CFrame.new(((s/10)-2.65)-.05,2.78,0) else _key.Color = Color3.new(1,1,1) _key.Size = Vector3.new(.1,.65,0) _keyweld.C0 = CFrame.new((s/10)-2.65,2.87,0) s+=1 end end end local colors = { ['0'] = Color3.fromRGB(255,0,0), -- Red ['1'] = Color3.fromRGB(255,127,0), -- Orange ['2'] = Color3.fromRGB(255,255,0), -- Yellow ['3'] = Color3.fromRGB(0,255,0), -- Green ['4'] = Color3.fromRGB(0,0,255), -- Blue ['5'] = Color3.fromRGB(75,0,130), -- Indigo ['6'] = Color3.fromRGB(148,0,211), -- Violet ['7'] = Color3.fromRGB(238,130,238), -- Lavender ['8'] = Color3.fromRGB(218,112,214), -- Pink ['10'] = Color3.fromRGB(221,160,221), -- Plum ['11'] = Color3.fromRGB(238,232,170), -- Beige ['12'] = Color3.fromRGB(255,250,250), -- Peach ['13'] = Color3.fromRGB(255,235,205), -- Coral ['14'] = Color3.fromRGB(255,69,0), -- Tomato ['15'] = Color3.fromRGB(240,230,140), -- Khaki ['16'] = Color3.fromRGB(240,248,255) -- Alice Blue } function highlightKey (note,time,channel) if(note >= 88) then return end --warn(channel) local saveColor local key = mainPart[tostring(note)] key.Material = 'Neon' key.Color = colors[tostring(channel)] task.delay(time,function() if (table.find(blackKeys,key.Name)) then key.Color = Color3.new() else key.Color = Color3.new(1,1,1) end key.Material = 'SmoothPlastic' end) end function Song:_parse(event) --[[ Event: Event name [String] Start time [Number] ... Note: Event name [String] Start time [Number] Duration [Number] Channel [Number] Pitch [Number] Velocity [Number] ]] local eventName = event[1] if (eventName == "set_tempo") then self._usPerBeat = event[3] elseif (eventName == "song_position") then self.TimePosition = (event[3] / self.Timebase) print("set timeposition timebase", self.Timebase) end local audio; if (eventName == "note") then if(event[4]==9) then --print(event[5]) local Percussion = { -- Bass Drum ['35'] = {'rbxassetid://31173820', 1}, ['36'] = {'rbxassetid://31173820', 1}, --IDK ['82'] = {'rbxassetid://31173898', 1}, --Conga ['62'] = {'rbxassetid://57802212', 1}, --high ['63'] = {'rbxassetid://57802212', 1}, --high ['64'] = {'rbxassetid://57802134', 1}, -- low --Conga ['60'] = {'rbxassetid://57802055', 1}, --high ['61'] = {'rbxassetid://57801983', 1}, -- low --Toms ['45'] = {'rbxassetid://31173881', 1}, -- low ['47'] = {'rbxassetid://31173863', 1}, -- lowmid ['48'] = {'rbxassetid://31173863', 1}, -- highmid ['50'] = {'rbxassetid://31173844', 1}, -- high --Cowbell ['56'] = {'rbxassetid://9120917609', 1}, --Cymbals ['49'] = {'rbxassetid://31173771', 1}, -- Crash ['51'] = {'rbxassetid://31173898', 1}, -- Ride ['57'] = {'rbxassetid://31173771', 1}, -- Crash ['59'] = {'rbxassetid://31173898', 1}, -- Ride ['42'] = {'rbxassetid://4702649974', 1}, --HiHat Closed ['44'] = {'rbxassetid://31173735', 1}, --HiHat ['46'] = {'rbxassetid://31173735', 1}, --HiHat --Tambourine ['54'] = {'rbxassetid://1840229078', 1, .140,4.263}, --Sound Effects ['39'] = {'rbxassetid://9114763106', 1},--clap ['28'] = {'rbxassetid://9126213464', 1, .1},--whip --Cabasa ['69'] = {'rbxassetid://1841124373', 1, .136, .340}, --Maracas ['70'] = {'rbxassetid://1844421271', 1, .236, .211}, -- Cuica ['78'] = {'rbxassetid://7430849680', 1}, ['79'] = {'rbxassetid://7430849680', 1}, -- Snare ['38'] = {'rbxassetid://31173799', 1}, ['40'] = {'rbxassetid://31173799', 1}, --Triangle ['80'] = {'rbxassetid://9116223900', 1}, ['81'] = {'rbxassetid://9116223333', 1}, -- Castanets ['85'] = {'rbxassetid://1840247421', 1, .348, .057}, -- Wood Blocks ['76'] = {'rbxassetid://9120917978', 1}, ['77'] = {'rbxassetid://9120917605', 1}, } --percussionBillboard.Size = UDim2.new(10, 0, 1, 0) --game:GetService('TweenService'):Create(percussionBillboard,TweenInfo.new(.25),{ -- Size = UDim2.new(10, 0, 0.7, 0) --}):Play() if(not Percussion[tostring(event[5])]) then warn('Instrument','#'..event[5],'is not setup') return else --warn(Percussion[tostring(event[5])]) end local Instrument = Percussion[tostring(event[5])] audio = Instance.new("Sound", owner.Character.Head)-- Create the audio audio.SoundId = Instrument[1] audio.Pitch = Instrument[2] audio.Volume = event[6]/127 audio.Name = tick() audio.RollOffMaxDistance = 100 if(Instrument[3]) then audio.TimePosition = Instrument[4] end if(Instrument[4]) then task.delay(Instrument[3],function() audio:Stop() end) end audio:Resume() game:GetService("Debris"):AddItem(audio,8) else --warn(event[4]) --pianoBillboard.Size = UDim2.new(10, 0, 1, 0) --game:GetService('TweenService'):Create(pianoBillboard,TweenInfo.new(.25),{ -- Size = UDim2.new(10, 0, 0.7, 0) --}):Play() playNote(event[5]-35,event[3] / self.Timebase,event[6]/127) highlightKey(event[5]-8,event[3] / self.Timebase,event[4]) end --Input.Hold(event[5], event[3] / self.Timebase) end end local newSong = Song.new('https://github.com/malice-cli/shit-midis/blob/main/Antarctic_Reinforcement.mid?raw=true') print(newSong.FullName) print(newSong._score ) newSong:Play()